package com.sc.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.relation.RelationManager;
import com.mybatisflex.core.update.UpdateWrapper;
import com.mybatisflex.core.util.UpdateEntity;
import com.mybatisflex.spring.service.impl.CacheableServiceImpl;
import com.sc.dto.EmpPageDTO;
import com.sc.dto.LoginDTO;
import com.sc.dto.ModifyPasswdDTO;
import com.sc.entity.Emp;
import com.sc.entity.Menu;
import com.sc.entity.table.EmpTableDef;
import com.sc.exception.ServiceException;
import com.sc.mapper.DeptMapper;
import com.sc.mapper.EmpMapper;
import com.sc.result.Result;
import com.sc.result.ResultCode;
import com.sc.service.EmpService;
import com.sc.util.JwtUtil;
import com.sc.util.RegexUtil;
import com.sc.vo.LoginVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;
import java.sql.Date;

import static com.mybatisflex.core.query.QueryMethods.max;
import static com.sc.entity.table.EmpTableDef.EMP;
//import QueryMethods

/**
 * 员工表 服务层实现。
 *
 * @author JoeZhou
 * @since 2024-09-11
 */
@Service
@CacheConfig(cacheNames = "emp")
public class EmpServiceImpl extends CacheableServiceImpl<EmpMapper, Emp> implements EmpService {
    @Autowired
    private DeptMapper deptMapper;

    /**
     * 为新员工生成编号：当前系统中最大编号+1
     * 如果考虑集群部署时，需要添加分布式锁；也可以考虑使用Redis来生成员工编号
     * @return
     */
    private synchronized String nextEno() {
        QueryWrapper query = new QueryWrapper()
                .select(max(EMP.ENO)).from(EMP);
        String maxEno = mapper.selectOneByQueryAs(query, String.class);
        if (maxEno == null) {
            return "E10000";
        } else {
            return "E" + (Integer.valueOf(maxEno.substring(1)) + 1);
        }
    }


    @Override
    @CacheEvict(allEntries = true)
    public Emp register(Emp entity) {
        String newEno = nextEno();
        entity.setEno(newEno);
        // 手机号后6位做密码
        String passwd = entity.getPhone().substring(5);
        // 使用md5对密码加密
        entity.setPasswd(SecureUtil.md5(passwd));
//        if (entity.getHiredate() == null) {
//            entity.setHiredate(new Date(System.currentTimeMillis()));
//        }

        this.save(entity);
        // 查询一下该员工的信息及其部门信息
        Emp emp = this.getById(entity.getId());
        emp.setDept(deptMapper.selectOneById(emp.getDeptId()));
        return emp;
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #empPageDTO.getPageSize() + ':' + #empPageDTO.getPageNum() ")
    public Page<Emp> page(EmpPageDTO empPageDTO) {
        Page<Emp> page = new Page<>(empPageDTO.getPageNum(), empPageDTO.getPageSize());
        RelationManager.addIgnoreRelations("roles");
        QueryWrapper queryWrapper = new QueryWrapper();
        if (empPageDTO.getName() != null) {
            queryWrapper.like("name", empPageDTO.getName());
        }
        if (empPageDTO.getPhone() != null) {
            queryWrapper.eq("phone", empPageDTO.getPhone());
        }
        if (empPageDTO.getDeptId() != null) {
            queryWrapper.eq("dept_id", empPageDTO.getDeptId());
        }
        return mapper.paginateWithRelations(page, queryWrapper);
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean modifyPasswd(String phone, String oldPasswd, String newPasswd) {
        /*Emp emp = mapper.selectOneByQuery(
                QueryWrapper.create()
                    .where(EMP.PHONE.eq(phone))
        );*/
        QueryWrapper queryWrapper = QueryWrapper.create();
        queryWrapper.where(EMP.PHONE.eq(phone));
//        queryWrapper.eq("phone", phone);
        Emp emp = mapper.selectOneByQuery(queryWrapper);
        if (emp == null)
            throw new ServiceException("手机号码错误");
        if (!emp.getPasswd().equals(SecureUtil.md5(oldPasswd)))
            throw new ServiceException("旧密码错误");
        Emp entity = UpdateEntity.of(Emp.class, emp.getId());
        // 设置新密码
        entity.setPasswd(SecureUtil.md5(newPasswd));
        entity.setUpdated(LocalDateTime.now());
        return mapper.update(entity) > 1;
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean modifyPasswd(ModifyPasswdDTO dto) {
        Emp emp = mapper.selectOneById(dto.getId());

        if (emp == null)
            throw new ServiceException("手机号码错误");
        if (!emp.getPasswd().equals(SecureUtil.md5(dto.getOldPasswd())))
            throw new ServiceException("旧密码错误");
        Emp entity = UpdateEntity.of(Emp.class, emp.getId());
        // 设置新密码
        entity.setPasswd(SecureUtil.md5(dto.getNewPasswd()));
        entity.setUpdated(LocalDateTime.now());
        entity.setVersion(emp.getVersion());
        return mapper.update(entity) > 0;
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean resetPasswd(Long id) {
        Emp emp = mapper.selectOneById(id);

        if (emp == null)
            throw new ServiceException("员工ID不存在");
        Emp entity = UpdateEntity.of(Emp.class, emp.getId());
        // 设置新密码为手机号码后6位
        entity.setPasswd(SecureUtil.md5(emp.getPhone().substring(5)));
        entity.setUpdated(LocalDateTime.now());
        entity.setVersion(emp.getVersion());
        return mapper.update(entity) > 0;
    }

    @Override
    @Cacheable(key = "#root.methodName")
    public Map<String, Object> livingEmp() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("status", 1);
        long total = mapper.selectCountByQuery(queryWrapper);
        // 获得这一年年初的时间点 20xx-01-01T00:00
        LocalDateTime yearStartDateTime = LocalDateTime.now().toLocalDate().withMonth(1).withDayOfYear(1).atStartOfDay();
        queryWrapper.gt("hiredate", yearStartDateTime);
        long increase = mapper.selectCountByQuery(queryWrapper);
        Map<String, Object> result = new HashMap<>();
        result.put("livingEmp", total);
        result.put("increase", increase);
        return result;
    }


    @Override
    public LoginVO login(LoginDTO dto) {
        RelationManager.setMaxDepth(4);
        //        authenticate(emp.getUsername(), emp.getPasswd());
        final String username = dto.getUsername();

        Emp emp = null;
        // 手机号登录
        if (RegexUtil.isValidPhoneNumber(username)) {
            emp = mapper.selectOneWithRelationsByQuery(QueryWrapper.create()
                    .where(EMP.PHONE.eq(username))
                    .and(EMP.PASSWD.eq(SecureUtil.md5(dto.getPasswd()))));
        }
        // 员工编号登录
        else {
            emp = mapper.selectOneWithRelationsByQuery(QueryWrapper.create()
                    .where(EMP.ENO.eq(username))
                    .and(EMP.PASSWD.eq(SecureUtil.md5(dto.getPasswd()))));
        }
        // 检查记录是否存在
        if (ObjectUtil.isNull(emp)) {
            throw new ServiceException("账号密码错误");
        }

        String token = JwtUtil.build(emp.getId(), emp.getName());


        // 处理会员菜单列表
        List<Menu> menus = new ArrayList<>();
        emp.getRoles().forEach(role -> role.getMenus().forEach(menu -> {
            // 仅组装根权限
            if (menu.getPid() == 0) {
                menus.add(menu);
            }
        }));
        emp.setRoles(null);
        LoginVO loginVO = new LoginVO();
        loginVO.setMenus(menus);
        loginVO.setEmp(emp);
        loginVO.setToken(token);

        return loginVO;
    }


    @Override
    @CacheEvict(allEntries = true)
    public boolean remove(QueryWrapper query) {
        return super.remove(query);
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean removeById(Serializable id) {
        return super.removeById(id);
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean removeByIds(Collection<? extends Serializable> ids) {
        return super.removeByIds(ids);
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean update(Emp entity, QueryWrapper query) {
        return super.update(entity, query);
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean updateById(Emp entity, boolean ignoreNulls) {
        return super.updateById(entity, ignoreNulls);
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean updateBatch(Collection<Emp> entities, int batchSize) {
        return super.updateBatch(entities, batchSize);
    }

    @Override
    @Cacheable(key = "#id")
    public Emp getById(Serializable id) {
        RelationManager.addIgnoreRelations("roles");
        return mapper.selectOneWithRelationsById(id);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public Emp getOne(QueryWrapper query) {
        return super.getOne(query);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public <R> R getOneAs(QueryWrapper query, Class<R> asType) {
        return super.getOneAs(query, asType);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public Object getObj(QueryWrapper query) {
        return super.getObj(query);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public <R> R getObjAs(QueryWrapper query, Class<R> asType) {
        return super.getObjAs(query, asType);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public List<Object> objList(QueryWrapper query) {
        return super.objList(query);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public <R> List<R> objListAs(QueryWrapper query, Class<R> asType) {
        return super.objListAs(query, asType);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public List<Emp> list(QueryWrapper query) {
        return super.list(query);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public <R> List<R> listAs(QueryWrapper query, Class<R> asType) {
        return super.listAs(query, asType);
    }

    /**
     * @deprecated 无法通过注解进行缓存操作。
     */
    @Override
    @Deprecated
    public List<Emp> listByIds(Collection<? extends Serializable> ids) {
        return super.listByIds(ids);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public long count(QueryWrapper query) {
        return super.count(query);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #page.getPageSize() + ':' + #page.getPageNumber() + ':' + #query.toSQL()")
    public <R> Page<R> pageAs(Page<R> page, QueryWrapper query, Class<R> asType) {
        return mapper.paginateWithRelationsAs(page.getPageNumber(), page.getPageSize(), query, asType);
    }


}
